// ============================================================================
// Name        : tp1-decode.s
// Authors     : Galli, Nadia
// 		 Pivetta, Agustin
// 		 Tkaczyszyn, Facundo
// Version     : 1.0
// Description : Tp1 66.20: Programacion MIPS
// ============================================================================
// Inicio del codigo
#include <mips/regdef.h>

.text
.align 2
// ============================================================================
// Esta funcion realiza el decoding de '1's y '0's y los vuelca a stdout
// size_t decode(char *c)
// Diagrama de Stack
// 40 - [__a0__]_____________________
// 36 - [  pad ]
// 32 - [  ra  ] Saved Register Area
// 28 - [  fp  ]
// 24 - [  gp  ]_____________________
// 20 - [      ] Local and Temporary Area
// 16 - [      ]_____________________
// 12 - [      ] 
// 8  - [      ] Argument Building
// 4  - [      ] Area
// 0  - [      ]_____________________

.global decode
.ent decode

decode:
        .frame $fp,40,ra
	.set noreorder
	.cpload t9
	.set reorder
    
        // creo stack frame
        subu sp,sp,40   	#Reservo 40 Bytes (16 para parametros, 16 para respaldar los valores de fp, gp, ra, 8 para LTA)
        .cprestore 24

        sw ra,32(sp)		#Respaldo la posicion de la return address
        sw $fp,28(sp)		#Respaldo la posicion del frame pointer
	sw gp,24(sp)		#Respaldo la posicion del global pointer
	move $fp,sp
        sw a0,40($fp)		# guardo el argumento 0 en el ABA del caller

	// Inicializo registros
	li t0, 0		#t0 es i = 0, contador de loop
	move t1, zero		#t1 es el char que vamos decodificar
	move t4, a0		#paso la direccion del buffer a t4
	la t2, mascara_bits	

dec_for:
	li t3,8
	beq t0,t3,dec_endloop	#Se termino el for
	lbu t5,0(t4)		#Leo un char de buffer	
	addi t4,t4,1		#sumo el offset
	lbu t6, cero(zero)	#Leo un ascii "0" para usar de referencia en el EQ
	beq t5,t6,dec_is_zero
	lbu t6, uno(zero)	#Leo un ascii "1" para verificar que el archivo no este mal formado	
	bne t5,t6,dec_ferror	#format error
	
	lbu t3, 0(t2)		#leo la mascara
	addi t2,t2,1		#sumo el offset al vector de mascaras
	or t1,t1,t3		#Pongo en 1 el bit correspondiente
	addi t0, t0, 1		#Aumento en 1 el contador
	b dec_for		#Loopea una vez mas

dec_is_zero:
	// no tengo que hacer nada, aumento el index y loopeo de nuevo
	addi t0, t0, 1		#Aumento en 1 el contador
	addi t2,t2,1		#sumo el offset al vector de mascaras
	b dec_for		#Loopea una vez mas

dec_endloop:
	li a0, 1		#Guardo 1 porque quiero escribir al stdout
	sb t1,wbuffer(zero)	#Guardo el char a escribir en el buffer
	la a1, wbuffer		#Le paso el bufer
	li a2, 1		#Guardo 1 porque quiero escribir solo un byte
	jal write_asm		#Mando a escribir el caracter
	bne v1, zero, dec_werror	#Write error
	li v0,0			#Codigo OK
	b encode_end

dec_ferror:
	li v0, 4 		#Muevo el codigo de error al retorno de la funcion y salgo de esta
	b encode_end

dec_werror:
	li v0, 5 		#Muevo el codigo de error al retorno de la funcion y salgo de esta
	b encode_end

encode_end:
        lw ra,32($fp)		#Recupero la posicion del return address
	lw $fp,28($fp)		#Recupero la posicion del frame pointer
	lw gp,24($fp)		#Recupero la posicion del global pointer
	addu sp,sp,40
	j ra
	
.end decode

// ============================================================================
// Este programa genera decodifica el texto de un volcado de '1's y '0's ingresado por stdin
// int main(int argc, char *argv[]);

// Diagrama de Stack
// 36 - [  a1  ]
// 32 - [__a0__]_____________________
// 28 - [  pad ]
// 24 - [  ra  ] Saved Register Area
// 20 - [  fp  ]
// 16 - [  gp  ]_____________________
// 12 - [      ] 
// 8  - [      ] Argument Building
// 4  - [      ] Area
// 0  - [      ]_____________________

.global main
.ent main

main:
        .frame $fp,32,ra
	.set noreorder
	.cpload t9
	.set reorder
    
        // creo stack frame
        subu sp,sp,32   	#Reservo 32 Bytes (16 para parametros, 16 para respaldar los valores de fp, gp, ra)
        .cprestore 16

        sw ra,24(sp)		#Respaldo la posicion de la return address
        sw $fp,20(sp)		#Respaldo la posicion del frame pointer
	sw gp,16(sp)		#Respaldo la posicion del global pointer
	move $fp,sp
        sw a0,32($fp)		# guardo el argumento 0 en el ABA del caller
        sw a0,36($fp)		# guardo el argumento 1 en el ABA del caller

	move v0, zero		#Inicializa en cero el retorno de la funcion

main_while:
	//leo de stdin
	li a0, 0		#Guardo 0 porque quiero leer del stdin
	la a1, rbuffer		#Paso el buffer de lectura
	li a2, 8		#Guardo 8 porque quiero leer un "byte" de '0's y '1's
	jal read_asm		
	bne v1,zero,main_error	#Verifica errores
	li t0, 8
	bne t0,v0,main_error2	#Si no leyo 8 caracteres, analizo si es eof o archivo mal formado
	
	la t0,rbuffer(zero)	#Cargo el buffer leido
	move a0, t0		#Preparo el buffer leido como parametro de encode
	jal decode
	bnez v0,main_error3	#Sale del programa si hay error
	b main_while		#Loopea hasta que no haya nada mas que leer

main_error:
	li v0, 2 		#Muevo el codigo de error al retorno de la funcion y salgo de esta
	b main_end

main_error2:
	beqz v0,main_end	#Leyo 0 caracteres, es eof
	li v0, 3 		#Muevo el codigo de error al retorno de la funcion y salgo de esta
	// Escribo el mensaje de error
	li a0, 2		#stderr
	la a1, msg0		#Paso el buffer de lectura
	li a2, 59		
	jal write_asm	
	b main_end

main_error3:
	li t0, 4		#Codigo de error de caracter no binario
	bne v0,t0, main_end	#Si el error es 4 escribo el mensaje por stderr
	// Escribo el mensaje de error
	li a0, 2		#stderr
	la a1, msg1		#Paso el buffer de lectura
	li a2, 49		
	jal write_asm	
	b main_end

main_end:
        lw ra,24(sp)		#Recupero la posicion del return address
	lw $fp,20(sp)		#Recupero la posicion del frame pointer
	lw gp,16(sp)		#Recupero la posicion del global pointer
	addu sp,sp,32
	j ra
.end main

// ============================================================================
// Datos
.data
.align 2

// Mensaje de error por archivo mal formado
msg0:		.asciiz "\nError de lectura, el archivo finaliza de forma inesperada\n"
msg1:		.asciiz "\nError, el caracter leido no es un valor binario\n"

// Buffer de lectura/escritura
rbuffer:	.byte 0,0,0,0,0,0,0,0
wbuffer:	.byte 0

// Mascara para sacar los bits de un byte
mascara_bits:	.byte 128,64,32,16,8,4,2,1

// Constantes
cero:		.ascii "0" #Declaro el cero
uno:		.ascii "1" #Declaro el uno
